import random
import string

from common.tools import Tool
from common.conf import conf


class Protocol:
    def __init__(self):
        self.t = Tool()
        self.c = conf

    def register_ok(self, s):  # s 是register  msg
        call_id = self.t.line_by_word(s, "Call-ID:")
        from_s = self.t.line_by_word(s, "From:")
        to_s = self.t.line_by_word(s, "To:")
        via = self.t.line_by_word(s, "Via:")
        cseq = self.t.line_by_word(s, "CSeq:")
        s = 'SIP/2.0 200 OK\n'
        s += f"Via: {via}\n"
        s += f"From: {to_s}\n"
        s += f"To: {from_s}\n"
        s += f"Call-ID: {call_id}\n"
        s += f"CSeq: {cseq}\n"
        return s

    # TODO 请求设备视频流 这msg是message call id 作为 y,会被zlmeidalkit 按照cid2ssrc的逻辑转化成视频url stream id  . call_id bye的是一样,
    #  所以存入redis,可以bye的时候继续invit https://blog.yasking.org/a/hikvision-nvr-playback-with-gb28181.htmle
    def invite(self, msg, cam_id_short, chan_id, cam_ip, cam_port):
        # cid = ''.join(random.choices(string.digits, k=8))
        cid = self.t.from_camId_chanId_to_cid(cam_id_short, chan_id)
        tag = ''.join(random.choices(string.digits, k=10))
        branch = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
        # y = ''.join(random.choices(string.digits, k=6))

        cam_id_long = msg[(msg.find('From:') + 11):msg.find('>', msg.find('From:'))]

        sip_id_short = self.c.sip_id

        p = f"v=0\r\n"
        p += f"o={cam_id_long} 0 0 IN IP4 {self.c.zl_ip}\r\n"
        p += f"s=Play\r\n"  # Playback
        # p += f"s=Playback\r\n"  # Playback

        p += f"c=IN IP4 {self.c.zl_ip}\r\n"  # 流媒体ip

        p += f"t=0 0\r\n"  # t=1667584166 1667597055 s=Playback

        # 传输协议TCP被动动模式
        p += f"m=video {self.c.zl_port} RTP/AVP 96 97 98 99\r\n"
        # p += f"m=video {self.c.zl_port} TCP/RTP/AVP 96 97 98 99\r\n"
        # p += f"a=setup:passive\r\n"
        # p += f"a=connection:new\r\n"

        p += f"a=rtpmap:96 PS/90000\r\n"
        p += f"a=rtpmap:97 MPEG4/90000\r\n"
        p += f"a=rtpmap:98 H264/90000\r\n"
        p += f"a=rtpmap:99 H265/90000\r\n"
        p += f"a=recvonly\r\n"
        # sdp 中穿进去 y=cid,生成url ssrc
        p += f"y={cid}\r\n"

        s = f'INVITE sip:{chan_id}@{cam_ip}:{cam_port} SIP/2.0\n'
        s += f"Via: SIP/2.0/UDP {self.c.sip_ip}:{self.c.sip_port};rport;branch={branch}\n"
        s += f"From: <sip:{sip_id_short}@{self.c.sip_ip}>;tag={tag}\n"
        s += f"To: <sip:{chan_id}@{cam_ip}:{cam_port}>\n"
        s += f"Call-ID: {cid}\n"
        s += f"CSeq: 20 INVITE\n"
        s += f"Max-Forwards: 70\n"
        s += f"Contact: <sip:{sip_id_short}@{self.c.sip_ip}:{self.c.sip_port}>\n"
        s += f"Content-Type: application/sdp\n"
        # 必须携带Subject头域，值为 摄像头通道ID:通道号,通道ID(主叫的sip id):通道号
        # s += f"Subject: {cam_id_short}:0,{sip_id_short}:0\n"
        s += f"Subject: {chan_id}:0,34020000002000000001:0\n"
        s += f"Allow: INVITE,ACK,OPTIONS,BYE,CANCEL, UPDATE ,PRACK,REFER,SUBSCRIBE,NOTIFY,MESSAGE\n"
        s += f"Content-Length: {len(p)}\n\n"
        s += p
        return cid, s

    def ack_invite(self, msg):  # 这个msg是invite回复
        call_id = self.t.line_by_word(msg, "Call-ID:")
        cam_id = msg[(msg.find('To:') + 9):msg.find('>', msg.find('To:'))]
        from_s = self.t.line_by_word(msg, "From:")
        to_s = self.t.line_by_word(msg, "To:")
        via = self.t.line_by_word(msg, "Via:")

        s = f"ACK sip:{cam_id} SIP/2.0\n"
        s += f"Via: {via}\n"
        s += f"From: {from_s}\n"
        s += f"To: {to_s}\n"
        s += f"Call-ID: {call_id}\n"
        s += f"CSeq: 20 ACK\n"
        s += f"Max-Forwards: 70\n"
        s += f"Content-Length: 0\n"

        return s

    def bye(self, msg):  # bye
        call_id = self.t.line_by_word(msg, "Call-ID:")
        # cam_id = msg[(msg.find('from:') + 9):msg.find('>', msg.find('To:'))]
        from_s = self.t.line_by_word(msg, "From:")
        to_s = self.t.line_by_word(msg, "To:")
        via = self.t.line_by_word(msg, "Via:")
        bye = self.t.line_by_word(msg, "CSeq:")
        s = "SIP/2.0 200 OK\n"
        s += f"Via: {via}\n"
        s += f"From: {to_s}\n"
        s += f"To: {from_s}\n"
        s += f"Call-ID: {call_id}\n"
        s += f"CSeq: {bye}\n"
        s += f"Content-Length: 0\n"
        return s

    def query(self, cam_id, chan_id, cam_ip, cam_port):
        sip_id = self.c.sip_id
        domain = self.c.sip_domain
        p = '<?xml version="1.0" encoding="gb2312"?>\n'
        p += "<Query>\n"
        p += "<CmdType>RecordInfo</CmdType>\n"
        p += "<SN>840887582</SN>\r\n"
        p += f"<DeviceID>{chan_id}</DeviceID>\n"
        p += "<StartTime>2023-11-16T12:00:00</StartTime>\n"
        p += "<EndTime>2023-11-02T15:59:00</EndTime>\n"
        p += "<Type>all</Type>\n"
        p += "</Query>\n"

        cid = ''.join(random.choices(string.digits, k=8))
        tag = ''.join(random.choices(string.digits, k=10))
        branch = ''.join(random.choices(string.ascii_letters + string.digits, k=16))

        s = f'MESSAGE sip:{sip_id}@{domain} SIP/2.0\n'
        s += f"Via: SIP/2.0/UDP {cam_ip}:{cam_port};rport;branch={branch}\n"
        s += f"From: <sip:{sip_id}@{self.c.sip_ip}:{self.c.sip_port}>;tag={tag}\n"
        s += f"To: <sip:{chan_id}@{cam_ip}:{cam_port}>\n"
        s += f"Call-ID: {cid}\n"
        s += f"CSeq: 20 MESSAGE\n"
        s += "Content-Type: Application/MANSCDP+xml\n"
        s += f"Content-Length: {len(p)}\n\n"

        s += p
        return s

    # from to callid对应 其中to tag是invite ok设备给的,在回答ack之前通过call id保存(此刻不知道chan),其他invite的时候就知道
    def bye_invite(self, msg, to_tag):  # bye
        print(msg)

        invite = self.t.line_by_word(msg, "INVITE")
        call_id = self.t.line_by_word(msg, "Call-ID:")
        # cam_id = msg[(msg.find('from:') + 9):msg.find('>', msg.find('To:'))]
        from_s = self.t.line_by_word(msg, "From:")
        to_s = self.t.line_by_word(msg, "To:")
        via = self.t.line_by_word(msg, "Via:")
        cseq = self.t.line_by_word(msg, "CSeq:")

        s = f"BYE {invite}\n"
        s += f"Via: {via}\n"
        s += f"From: {from_s}\n"
        s += f"To: {to_s};tag={to_tag}\n"
        s += f"Call-ID: {call_id}\n"
        s += f"CSeq: 211 BYE\n"
        s += f"Content-Length: 0\n"
        print(s)
        return s


if __name__ == '__main__':
    s = '''MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.120:5060;rport;branch=z9hG4bK1665067055
From: <sip:34020000001320000001@3402000000>;tag=1516035905
To: <sip:34020000002000000001@3402000000>
Call-ID: 1081077839
CSeq: 20 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: IP Camera
Content-Length:   177

<?xml version="1.0" encoding="GB2312"?>
<Notify>
<CmdType>Keepalive</CmdType>
<SN>33</SN>
<DeviceID>34020000001320000001</DeviceID>
<Status>OK</Status>
<Info>
</Info>
</Notify>'''
    m = Protocol()
    a = m.query()
    print(a.encode())
